/* --- 使用Queue --- 

队列（Queue）是一种经常使用的集合。

Queue实际上是实现了一个先进先出（FIFO：First In First Out）的'有序表'。

Queue和List的区别在于，List可以在任意位置添加和删除元素，而Queue只有两个操作：
    · 把元素添加到队列末尾（rear)；
    · 从队列头部(front)取出元素。


例如：超市的收银台的排队就是一个队列;

在Java的标准库中，队列接口Queue定义了以下几个方法

    1. int size()：获取队列长度；
    2。 boolean add(E) / boolean offer(E)：添加元素到队尾；
    3. E remove() / E poll()：获取队首元素并从队列中删除；
    4. E element() / E peek()：获取队首元素但并不从队列中删除。



对于具体的实现类，有的Queue有最大队列长度限制，有的Queue没有。注意到添加、删除和获取队列元素总是有两个方法，这是因为在添加或获取元素失败时，这两个方法的行为是不同的。我们用一个表格总结如下：

                 throw Exception	    返回false或null
添加元素到队尾	    add(E e)	        boolean offer(E e)
取队首元素并删除	E remove()	        E poll()
取队首元素但不删除	E element()	        E peek()

-------------------------

举个栗子，假设我们有一个Queue，对它做一个add操作，如果调用add()方法，当添加失败时（可能超过了队列的容量），它会抛出异常：   */
Queue<String> q = new Queue<String>();

try {
    q.add("apple");
    System.out.println("添加成功");
} catch(IllegalStateException e) {
    System.out.println("添加失败");
}


/*
如果我们调用offer()方法来添加元素，当添加失败时，它不会抛异常，而是返回false：  */
Queue<String> q = new Queue<String>();

if (q.offer("Apple")) {
    System.out.println("添加成功");
} else {
    System.out.println("添加失败");
}


//当我们需要从Queue中取出队首元素时，如果当前Queue是一个空队列，调用remove()方法，它会抛出异常：
Queue<String> q = new Queue<String>();

try { 
    String s = q.remove();
    System.out.println("获取成功");
} catch (IllegalStateException e) {
    System.out.println("获取失败");
}


//如果我们调用poll()方法来取出队首元素，当获取失败时，它不会抛异常，而是返回null：
Queue<String> q = new Queue<String>();
String s = q.poll();

if (s != null) {
    System.out.println("获取成功");
} else {
    System.out.println("获取失败");
}

/*
因此，两套方法可以根据需要来选择使用。

!!! 注意：不要把null添加到Queue中，否则poll()方法返回null时，很难确定是取到了null元素还是Queue为空。

---------------------------

接下来我们以poll()和peek()为例来说说“获取并删除”与“获取但不删除”的区别。对于Queue来说，每次调用poll()，都会获取队首元素，并且获取到的元素已经从队列中被删除了:  */
import java.util.LinkedList;
import java.util.Queue;

public class Main {
    public static void main(String[] args) {
        Queue<String> q = new LinkedList<>();

        //添加3个元素到Queue
        q.offer("Apple");
        q.offer("Pear");
        q.offer("Banana");

        //从Queue中取出元素
        System.out.println(q.poll()); //Apple
        System.out.println(q.poll()); //Pear
        System.our.println(q.poll()); //Banana
        System.out.println(q.poll()); //null,因为Queue已空
    }
}


//如果用peek()，因为获取队首元素时，并不会从队列中删除这个元素，所以可以反复获取：
import java.util.LinkedList;
import java.util.Queue;

public class Main {
    public static void main(String[] args) {
        Queue<String> q = new LinkedList<>();

        //添加3个元素到Queue
        q.offer("Apple");
        q.offer("Pear");
        q.offer("Banana");

        //队首永远都是Apple,因为Peek()不会删除它
        System.out.println(q.peek()); //Apple
        System.out.println(q.peek()); //Apple
        System.out.println(q.peek()); //Apple
    }
}



//从上面的代码中，我们还可以发现，LinkedList即实现了List接口，又实现了Queue接口，但是，在使用的时候，如果我们把它当作List，就获取List的引用，如果我们把它当作Queue，就获取Queue的引用：

//这是一个List
List<String> list = new LinkedList<>();

//这是一个Queue
Queue<String> queue = new LinkedList<>();


//始终按照面向抽象编程的原则编写代码，可以大大提高代码的质量。



/*  --- 使用Queue の 小结 ---   

1.队列Queue实现了一个先进先出（FIFO）的数据结构:

    · 通过add() / offer()方法将元素添加到队尾；
    · 通过remove() / poll()从队首获取元素并删除；
    · 通过element() / peek()从队首获取元素但不删除。

2.要避免把null添加到Queue

3.规则
                     throw Exception	    返回false或null
添加元素到队尾	        add(E e)	        boolean offer(E e)
取队首元素并删除	    E remove()	            E poll()
取队首元素但不删除	    E element()	            E peek()


*/











